﻿using LD.BC;
using log4net.Core;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net.PeerToPeer.Collaboration;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml.Linq;

namespace LD.Host
{
    public class ETHModbus
    {
        private static short _id = 0;
        private static object _lock = new object();
        public ETHModbus() { }
        private static byte[] GetNo
        {
            get
            {
                lock (_lock)
                {
                    if (_id >= short.MaxValue)
                        _id = 0;

                    _id++;
                    return BitConverter.GetBytes(_id);
                }
            }
        }
        /// <summary>
        /// 读取输入
        /// </summary>
        /// <remarks>参照说明中的6.1数字量输入信号采集命令</remarks>
        /// <returns></returns>
        public static BitArray ReadIn()
        {
            return Read(2);
        }
        /// <summary>
        /// 读取输入
        /// </summary>
        /// <remarks>参照说明中的6.2数字量输出信号采集命令</remarks>
        /// <returns></returns>
        public static BitArray ReadOut()
        {
            return Read(1);
        }
        /// <summary>
        /// 设置输出信号
        /// </summary>
        /// <param name="no">点位(索引从0开始)</param>
        /// <param name="level">信号</param>
        /// <remarks>参照说明中的6.3数字量输出信号多个控制命令</remarks>
        /// <returns></returns>
        public static bool SetOut(short no, LevelType level)
        {
            var msg = GetNo;
            var adr = BitConverter.GetBytes(no);
            var val = level == LevelType.低电平 ? new byte[] { 0xFF, 0x00 } : new byte[] { 0x00, 0x00 };

            byte[] req = new byte[12];
            req[0] = msg[1];    //报文序号高位
            req[1] = msg[0];    //报文序号低位
            req[2] = 0x00;    //协议编号高位
            req[3] = 0x00;    //协议编号低位
            req[4] = 0x00;    //报文长度高位（后续长度）
            req[5] = 0x06;    //报文长度地位（后续长度）
            req[6] = 0x01;    //站号
            req[7] = 0x05;    //功能码
            req[8] = adr[1];    //写入地址
            req[9] = adr[0];    //写入地址
            req[10] = val[0];   //寄存器个数高位
            req[11] = val[1];   //寄存器个数低位   16个转换为16进制为10
            //Log4.Info("Modbus输出set请求:" + BitConverter.ToString(req));
            var rep = CommunicateFactory.Instance.TcpIp["ETH_Modbus"].Send(req);
            //Log4.Info("Modbus输出set返回:" + BitConverter.ToString(rep));
            if (rep != null)
            {
                return rep == req;
            }
            return false;
        }
        public static bool SetOut(string name, LevelType level)
        {
            var index = GetOut.Where(p => p.Name == name).FirstOrDefault();
            return SetOut((short)index.No, level);
        }
        public static LevelType ReadIn(string name)
        {
            var index = GetIn.Where(p => p.Name == name).FirstOrDefault();
            if (index != null)
            {
                var bitArray = ReadIn();
                return bitArray[index.No - 1] ? LevelType.低电平 : LevelType.高电平;
            }
            return LevelType.高电平;
        }
        public static LevelType ReadOut(short no)
        {
            var bitArray = ReadOut();
            return bitArray[no] ? LevelType.低电平 : LevelType.高电平;
        }
        /// <summary>
        /// 设置输出信号
        /// </summary>
        /// <param name="val">信号集合</param>
        /// <remarks>参照说明中的6.3数字量输出信号多个控制命令</remarks>
        public bool SetOut(BitArray bit)
        {
            string bin2Str1 = string.Empty;
            string bin2Str2 = string.Empty;
            for (int i = 8; i >= 0; i--)
            {
                bin2Str1 += bit[i] ? "1" : "0";
            }
            for (int i = 15; i >= 8; i--)
            {
                bin2Str2 += bit[i] ? "1" : "0";
            }
            var msg = GetNo;
            byte[] req = new byte[12];
            req[0] = msg[1];             //报文序号高位
            req[1] = msg[0];             //报文序号低位
            req[2] = 0x00;               //协议编号高位
            req[3] = 0x00;               //协议编号低位
            req[4] = 0x00;               //报文长度高位（后续长度）
            req[5] = 0x09;               //报文长度地位（后续长度）
            req[6] = 0x01;               //站号
            req[7] = 0x0F;               //功能码
            req[8] = 0x00;               //起始地址
            req[9] = 0x00;               //起始地址
            req[10] = 0x00;               //写入长度
            req[11] = 0x10;               //写入长度
            req[12] = 0x02;               //写入数据字节数
            req[13] = Convert.ToByte(bin2Str1, 2); //写入数据低位
            req[14] = Convert.ToByte(bin2Str2, 2); //写入数据高位   16个转换为16进制为10
            //Log4.Info("Modbus输出sets请求:" + BitConverter.ToString(req));
            var rep = CommunicateFactory.Instance.TcpIp["ETH_Modbus"].Send(req);
            //Log4.Info("Modbus输出sets返回:" + BitConverter.ToString(rep));
            if (rep != null
                && rep[0] == req[0]
                && rep[1] == req[1]
                && rep[2] == req[2]
                && rep[3] == req[3]
                && rep[4] == req[4]
                && rep[5] == 0x06
                && rep[6] == req[6]
                && rep[7] == req[7]
                && rep[8] == req[8]
                && rep[9] == req[9]
                && rep[10] == req[10]
                && rep[11] == req[11]
                )
            {
                return true;
            }
            return false;
        }
        private static BitArray Parse(byte[] source, byte[] data)
        {
            if (data[0] == source[0]
                && data[1] == source[1]
                && data[2] == source[2]
                && data[3] == source[3]
                )
            {
                //报文长度
                short len = BitConverter.ToInt16(new byte[] { data[5], data[4] }, 0);
                //数据长度

                int dataLen = data[8];
                var bin1 = Convert.ToString(data[data.Length - 2], 2).Reversal().PadRight(8, '0').ToList();
                var bin2 = Convert.ToString(data[data.Length - 1], 2).Reversal().PadRight(8, '0').ToList();

                BitArray bitArray = new BitArray(16);
                for (int i = 0; i < bin2.Count; i++)
                {
                    bitArray[i] = bin1[i] == '0' ? false : true;
                    bitArray[i + 8] = bin2[i] == '0' ? false : true;
                }

                return bitArray;
            }

            return null;
        }
        private static BitArray Read(short flag)
        {
            var msg = GetNo;
            byte[] req = new byte[12];
            req[0] = msg[1];    //报文序号高位
            req[1] = msg[0];    //报文序号低位
            req[2] = 0x00;    //协议编号高位
            req[3] = 0x00;    //协议编号低位
            req[4] = 0x00;    //报文长度高位（后续长度）
            req[5] = 0x06;    //报文长度地位（后续长度）
            req[6] = 0x01;    //站号
            req[7] = (byte)flag;    //功能码
            req[8] = 0x00;    //起始码高位
            req[9] = 0x00;    //起始码低位
            req[10] = 0x00;   //寄存器个数高位
            req[11] = 0x10;   //寄存器个数低位   16个转换为16进制为10
            //if (flag == 2)
            //    Console.WriteLine("Modbus读输入请求:" + BitConverter.ToString(req));
            ////Log4.Info("Modbus读输入请求:" + BitConverter.ToString(req));
            //else
            //    Log4.Info("Modbus读输出请求:" + BitConverter.ToString(req));
            if (!CommunicateFactory.Instance.TcpIp.ContainsKey("ETH_Modbus"))
            {
                MessageBox.Show("ETH_Modbus连接未配置", "警告");
                return null;
            }
            var rep = CommunicateFactory.Instance.TcpIp["ETH_Modbus"]?.Send(req);

            //if (flag == 2)
            //    Console.WriteLine("Modbus读输入返回:" + BitConverter.ToString(rep));
            ////Log4.Info("Modbus读输入返回:" + BitConverter.ToString(rep));
            //else
            //    Log4.Info("Modbus读输出返回:" + BitConverter.ToString(rep));
            if (rep != null)
            {
                return Parse(req, rep);
            }
            return null;
        }

        public static List<TB_IO> GetIn
        {
            get
            {
                List<TB_IO> io_in = new List<TB_IO> {
                    new TB_IO() { IoType=(int)IoType.输入,No=1,Name="检测OK"},
                    new TB_IO() { IoType=(int)IoType.输入,No=2,Name="检测NG"},
                    new TB_IO() { IoType=(int)IoType.输入,No=3,Name="准备"},
                    new TB_IO() { IoType=(int)IoType.输入,No=4,Name="备用"},
                };
                return io_in;
            }
        }
        public static List<TB_IO> GetOut
        {
            get
            {
                List<TB_IO> io_out = new List<TB_IO> {
                    new TB_IO() { IoType=(int)IoType.输出,No=0,Name="激光检测"},
                    new TB_IO() { IoType=(int)IoType.输出,No=1,Name="程序0"},
                    new TB_IO() { IoType=(int)IoType.输出,No=2,Name="程序1"},
                    new TB_IO() { IoType=(int)IoType.输出,No=3,Name="程序2"},
                    new TB_IO() { IoType=(int)IoType.输出,No=4,Name="程序3"},
                    new TB_IO() { IoType=(int)IoType.输出,No=5,Name="程序4"},
                    new TB_IO() { IoType=(int)IoType.输出,No=6,Name="程序5"},
                };
                return io_out;
            }
        }
    }
}
